package ro.ubbcluj.cs.damate.managers.administration;

import org.apache.commons.lang.RandomStringUtils;
import org.primefaces.context.RequestContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.stereotype.Component;
import ro.ubbcluj.cs.damate.managers.BaseView;
import ro.ubbcluj.cs.damate.persistence.entities.Group;
import ro.ubbcluj.cs.damate.persistence.entities.User;
import ro.ubbcluj.cs.damate.services.GroupService;
import ro.ubbcluj.cs.damate.services.UserService;
import ro.ubbcluj.cs.damate.services.mail.MailService;
import ro.ubbcluj.cs.damate.webutils.MessageProvider;

import javax.faces.model.SelectItem;
import java.io.Serializable;
import java.sql.Date;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Lóránd Fazakas (lfazakas)
 *         Date: 2013.03.25.
 *         Time: 22:39
 */
@Component
@Scope("view")
public class UserManager extends BaseView implements Serializable {

    @Autowired
    private AdministrationView administrationView;

    @Autowired
    private UserService userService;

    @Autowired
    private transient PasswordEncoder passwordEncoder;

    @Autowired
    private MailService mailService;

    @Autowired
    private GroupService groupService;

    private List<User> users;
    private List<User> filteredUsers;

    private boolean changePassword;
    private boolean sendConfirmationMail = true;
    private boolean sendConfirmationMailAboutActivation = true;
    private boolean stateModified;
    private Long selectedGroupId;
    private User newOrModifiedUserBean;

    private List<Group> groups;

    private void clean() {
        this.users = null;
        this.filteredUsers = null;
        this.newOrModifiedUserBean = null;
        this.groups = null;
        this.changePassword = false;
        this.sendConfirmationMail = true;
        this.sendConfirmationMailAboutActivation = true;
        this.stateModified = false;
        this.selectedGroupId = null;
    }

    public void save() {
        newOrModifiedUserBean.setPassword(passwordEncoder.encodePassword(newOrModifiedUserBean.getPassword(), null));
        newOrModifiedUserBean.setGroup(getGroupById(selectedGroupId));
        newOrModifiedUserBean.setRegistrationDate(new Date(System.currentTimeMillis()));
        newOrModifiedUserBean.setLastActive(new Timestamp(System.currentTimeMillis()));
        userService.create(newOrModifiedUserBean);
        if (sendConfirmationMail) {
            mailService.sendRegistrationConfirmation(newOrModifiedUserBean);
            if (newOrModifiedUserBean.isState()) {
                mailService.sendAccountActivation(newOrModifiedUserBean);
            }
        }
        clean();
        administrationView.switchPanel(AdministrationView.AdminPanel.LIST_USERS.name());
    }

    private Group getGroupById(Long groupId) {
        for (Group group : getGroups()) {
            if (group.getGroupId().equals(groupId)) {
                return group;
            }
        }
        return null;
    }

    public void update() {
        if (changePassword) {
            newOrModifiedUserBean.setPassword(passwordEncoder.encodePassword(newOrModifiedUserBean.getPassword(), null));
        }
        newOrModifiedUserBean.setGroup(getGroupById(selectedGroupId));
        userService.update(newOrModifiedUserBean);
        if (stateModified && sendConfirmationMailAboutActivation) {
            if (newOrModifiedUserBean.isState()) {
                mailService.sendAccountActivation(newOrModifiedUserBean);
            } else {
                mailService.sendAccountDeactivation(newOrModifiedUserBean);
            }
        }
        clean();
        administrationView.switchPanel(AdministrationView.AdminPanel.LIST_USERS.name());
    }

    public void edit(User user) {
        this.newOrModifiedUserBean = user;
        this.selectedGroupId = user.getGroup().getGroupId();
        administrationView.switchPanel(AdministrationView.AdminPanel.NEW_USER.name());
    }

    public void resetPassword() {
        String newPassword = RandomStringUtils.randomAlphabetic(8);
        newOrModifiedUserBean.setPassword(passwordEncoder.encodePassword(newPassword, null));
        userService.update(newOrModifiedUserBean);
        mailService.sendPasswordReset(newOrModifiedUserBean, newPassword);
        RequestContext.getCurrentInstance().addCallbackParam("passwordChanged", "true");
    }

    public void delete(User user) {
        userService.delete(user);
        clean();
    }

    public void cancel() {
        clean();
        administrationView.switchPanel(AdministrationView.AdminPanel.DESCRIPTION.name());
    }

    public void openPanel(String panelName) {
        clean();
        administrationView.switchPanel(panelName);
    }

    public List<SelectItem> getSexFilterOptions() {
        List<SelectItem> filterOptions = new ArrayList<SelectItem>();
        filterOptions.add(new SelectItem("", MessageProvider.getValue("Common.all")));
        filterOptions.add(new SelectItem("true", MessageProvider.getValue("adminPage.userManagement.users.sex.male")));
        filterOptions.add(new SelectItem("false", MessageProvider.getValue("adminPage.userManagement.users.sex.female")));
        return filterOptions;
    }

    public List<SelectItem> getStateFilterOptions() {
        List<SelectItem> filterOptions = new ArrayList<SelectItem>();
        filterOptions.add(new SelectItem("", MessageProvider.getValue("Common.all")));
        filterOptions.add(new SelectItem("true", MessageProvider.getValue("adminPage.userManagement.users.state.active")));
        filterOptions.add(new SelectItem("false", MessageProvider.getValue("adminPage.userManagement.users.state.inactive")));
        return filterOptions;
    }

    public List<User> getUsers() {
        if (users == null) {
            this.users = userService.findAll();
        }
        return users;
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }

    public List<User> getFilteredUsers() {
        return filteredUsers;
    }

    public void setFilteredUsers(List<User> filteredUsers) {
        this.filteredUsers = filteredUsers;
    }

    public User getNewOrModifiedUserBean() {
        if (newOrModifiedUserBean == null) {
            this.newOrModifiedUserBean = new User();
            this.newOrModifiedUserBean.setSex(true);
        }
        return newOrModifiedUserBean;
    }

    public void setNewOrModifiedUserBean(User newOrModifiedUserBean) {
        this.newOrModifiedUserBean = newOrModifiedUserBean;
    }

    public boolean isSendConfirmationMail() {
        return sendConfirmationMail;
    }

    public void setSendConfirmationMail(boolean sendConfirmationMail) {
        this.sendConfirmationMail = sendConfirmationMail;
    }

    public boolean isSendConfirmationMailAboutActivation() {
        return sendConfirmationMailAboutActivation;
    }

    public void setSendConfirmationMailAboutActivation(boolean sendConfirmationMailAboutActivation) {
        this.sendConfirmationMailAboutActivation = sendConfirmationMailAboutActivation;
    }

    public boolean isStateModified() {
        return stateModified;
    }

    public void setStateModified(boolean stateModified) {
        this.stateModified = stateModified;
    }

    public boolean isChangePassword() {
        return changePassword;
    }

    public void setChangePassword(boolean changePassword) {
        this.changePassword = changePassword;
    }

    public Long getSelectedGroupId() {
        return selectedGroupId;
    }

    public void setSelectedGroupId(Long selectedGroupId) {
        this.selectedGroupId = selectedGroupId;
    }

    public List<Group> getGroups() {
        if (groups == null) {
            this.groups = groupService.findAll();
        }
        return groups;
    }

    public void setGroups(List<Group> groups) {
        this.groups = groups;
    }
}
